{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## AND、OR和子文档和数组\n",
    "\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-16-52-34.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 显式AND查询和OR查询\n",
    "\n",
    "### 隐式AND查询与显式AND查询\n",
    "\n",
    "在学习MongoDB基本语法的时候，我们假如我们要查下：\n",
    "\n",
    "> 年龄大于20并且薪资大于9999的所有人\n",
    "\n",
    "那么MongoDB的查询语句写为：\n",
    "\n",
    "```python\n",
    "handler.find({'age': {'$gt': 20}, 'salary': {'$gt': 9999}})\n",
    "```\n",
    "\n",
    "此时，这里的`age`和`salary`两个条件需要同时满足，在逻辑上他们是“与”的关系。但是我并没有把`AND`这个关键字写出来，所以这叫做“隐式AND查询”。\n",
    "\n",
    "而所谓的“显式AND查询”，它的效果和上面的隐式查询是一样的，但是需要把“AND”关键字写出来，写为：\n",
    "\n",
    "```python\n",
    "handler.find({\n",
    "    '$and': [\n",
    "        {'age': {'$gt': 20}},\n",
    "        {'salary': {'$gt': 9999}}\n",
    "       ]\n",
    "   })\n",
    "```\n",
    "\n",
    "所以显示AND查询的基本语法为：\n",
    "\n",
    "```python\n",
    "# 这里的查询条件1、查询条件2、查询条件3均为字典\n",
    "handler.find({'$and': [查询条件1, 查询条件2, 查询条件3]})\n",
    "```\n",
    "\n",
    "\n",
    "### OR 查询\n",
    "\n",
    "OR查询只有显式的写法，表示多个条件只要其中一个满足即可。例如要查询：\n",
    "\n",
    "> 年龄大于20或者薪资大于9999\n",
    "\n",
    "那么查询语句可以写为：\n",
    "\n",
    "```python\n",
    "handler.find({'$or': [{'age': {'$gt': 20}}, {'salary': {'$gt': 9999}}]})\n",
    "```\n",
    "\n",
    "OR查询的基本语法为：\n",
    "\n",
    "```python\n",
    "\n",
    "# 这里的查询条件1、查询条件2、查询条件3均为字典\n",
    "handler.find({'$or': [查询条件1, 查询条件2, 查询条件3]})\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 如何生成练习数据？\n",
    "\n",
    "扫码关注微信公众号\n",
    "\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/qrcode.jpg)\n",
    "\n",
    "回复：\n",
    "\n",
    "> 数据库\n",
    "\n",
    "获取本书源代码，使用Python运行`chapter_7`文件夹中的`import_example_data_1.py`文件，即可在本地MongoDB中生成对应的练习数据example_data_1."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 初始化数据库连接\n",
    "\n",
    "import pymongo\n",
    "\n",
    "handler = pymongo.MongoClient().chapter_7.example_data_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 6, 'age': 27, 'salary': 6847, 'sex': '男'}\n",
      "{'id': 11, 'age': 27, 'salary': 5931, 'sex': '男'}\n",
      "{'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'id': 26, 'age': 28, 'salary': 2489, 'sex': '男'}\n",
      "{'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'id': 34, 'age': 27, 'salary': 2931, 'sex': '男'}\n",
      "{'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'id': 57, 'age': 26, 'salary': 4691, 'sex': '男'}\n",
      "{'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n",
      "{'id': 98, 'age': 26, 'salary': 4704, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 隐式AND查询所有age大于25并且salary小于8000并且sex为男的数据\n",
    "\n",
    "rows = handler.find({'age': {'$gt': 25}, 'salary': {'$lt': 8000}, 'sex': '男'}, {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 6, 'age': 27, 'salary': 6847, 'sex': '男'}\n",
      "{'id': 11, 'age': 27, 'salary': 5931, 'sex': '男'}\n",
      "{'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'id': 26, 'age': 28, 'salary': 2489, 'sex': '男'}\n",
      "{'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'id': 34, 'age': 27, 'salary': 2931, 'sex': '男'}\n",
      "{'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'id': 57, 'age': 26, 'salary': 4691, 'sex': '男'}\n",
      "{'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n",
      "{'id': 98, 'age': 26, 'salary': 4704, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 显式AND查询所有age大于25并且salary小于8000并且sex为男的数据\n",
    "\n",
    "\n",
    "rows = handler.find({\n",
    "    '$and': [\n",
    "        {'age': {'$gt': 25}},\n",
    "        {'salary': {'$lt': 8000}},\n",
    "        {'sex': '男'}]\n",
    "    },\n",
    "    {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 6, 'age': 27, 'salary': 6847, 'sex': '男'}\n",
      "{'id': 11, 'age': 27, 'salary': 5931, 'sex': '男'}\n",
      "{'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'id': 26, 'age': 28, 'salary': 2489, 'sex': '男'}\n",
      "{'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'id': 34, 'age': 27, 'salary': 2931, 'sex': '男'}\n",
      "{'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'id': 57, 'age': 26, 'salary': 4691, 'sex': '男'}\n",
      "{'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n",
      "{'id': 98, 'age': 26, 'salary': 4704, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 显式AND查询与隐式AND查询混用\n",
    "\n",
    "rows = handler.find({\n",
    "    '$and': [\n",
    "        {'age': {'$gt': 25}, 'salary': {'$lt': 8000}},\n",
    "        {'sex': '男'}]\n",
    "    },\n",
    "    {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 1, 'age': 29, 'salary': 2664, 'sex': '女'}\n",
      "{'id': 2, 'age': 19, 'salary': 3086, 'sex': '男'}\n",
      "{'id': 3, 'age': 15, 'salary': 7662, 'sex': '女'}\n",
      "{'id': 4, 'age': 23, 'salary': 7001, 'sex': '女'}\n",
      "{'id': 5, 'age': 24, 'salary': 8042, 'sex': '女'}\n",
      "{'id': 6, 'age': 27, 'salary': 6847, 'sex': '男'}\n",
      "{'id': 7, 'age': 16, 'salary': 8916, 'sex': '男'}\n",
      "{'id': 8, 'age': 24, 'salary': 5191, 'sex': '女'}\n",
      "{'id': 9, 'age': 23, 'salary': 6643, 'sex': '男'}\n",
      "{'id': 11, 'age': 27, 'salary': 5931, 'sex': '男'}\n",
      "{'id': 13, 'age': 25, 'salary': 3156, 'sex': '男'}\n",
      "{'id': 14, 'age': 29, 'salary': 8825, 'sex': '女'}\n",
      "{'id': 15, 'age': 29, 'salary': 7635, 'sex': '女'}\n",
      "{'id': 16, 'age': 18, 'salary': 4204, 'sex': '女'}\n",
      "{'id': 17, 'age': 20, 'salary': 5498, 'sex': '男'}\n",
      "{'id': 18, 'age': 17, 'salary': 4600, 'sex': '男'}\n",
      "{'id': 19, 'age': 26, 'salary': 3116, 'sex': '女'}\n",
      "{'id': 20, 'age': 23, 'salary': 6317, 'sex': '男'}\n",
      "{'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'id': 22, 'age': 15, 'salary': 1930, 'sex': '女'}\n",
      "{'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'id': 24, 'age': 27, 'salary': 8833, 'sex': '女'}\n",
      "{'id': 25, 'age': 15, 'salary': 2749, 'sex': '男'}\n",
      "{'id': 26, 'age': 28, 'salary': 2489, 'sex': '男'}\n",
      "{'id': 27, 'age': 21, 'salary': 3236, 'sex': '男'}\n",
      "{'id': 28, 'age': 27, 'salary': 7052, 'sex': '女'}\n",
      "{'id': 29, 'age': 26, 'salary': 7494, 'sex': '女'}\n",
      "{'id': 30, 'age': 24, 'salary': 1820, 'sex': '女'}\n",
      "{'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'id': 33, 'age': 28, 'salary': 9276, 'sex': '男'}\n",
      "{'id': 34, 'age': 27, 'salary': 2931, 'sex': '男'}\n",
      "{'id': 35, 'age': 16, 'salary': 2443, 'sex': '男'}\n",
      "{'id': 36, 'age': 15, 'salary': 2073, 'sex': '女'}\n",
      "{'id': 37, 'age': 27, 'salary': 9361, 'sex': '男'}\n",
      "{'id': 38, 'age': 20, 'salary': 6039, 'sex': '女'}\n",
      "{'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'id': 40, 'age': 29, 'salary': 2314, 'sex': '女'}\n",
      "{'id': 41, 'age': 19, 'salary': 3829, 'sex': '男'}\n",
      "{'id': 42, 'age': 21, 'salary': 2989, 'sex': '女'}\n",
      "{'id': 43, 'age': 18, 'salary': 3813, 'sex': '男'}\n",
      "{'id': 44, 'age': 22, 'salary': 6060, 'sex': '女'}\n",
      "{'id': 45, 'age': 25, 'salary': 5602, 'sex': '女'}\n",
      "{'id': 46, 'age': 18, 'salary': 7582, 'sex': '女'}\n",
      "{'id': 47, 'age': 27, 'salary': 8937, 'sex': '女'}\n",
      "{'id': 48, 'age': 21, 'salary': 4565, 'sex': '男'}\n",
      "{'id': 49, 'age': 26, 'salary': 6087, 'sex': '女'}\n",
      "{'id': 50, 'age': 23, 'salary': 4103, 'sex': '男'}\n",
      "{'id': 51, 'age': 19, 'salary': 2733, 'sex': '男'}\n",
      "{'id': 52, 'age': 29, 'salary': 9868, 'sex': '男'}\n",
      "{'id': 53, 'age': 24, 'salary': 8977, 'sex': '女'}\n",
      "{'id': 54, 'age': 25, 'salary': 6052, 'sex': '女'}\n",
      "{'id': 55, 'age': 23, 'salary': 3741, 'sex': '男'}\n",
      "{'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'id': 57, 'age': 26, 'salary': 4691, 'sex': '男'}\n",
      "{'id': 60, 'age': 18, 'salary': 1640, 'sex': '男'}\n",
      "{'id': 61, 'age': 28, 'salary': 7494, 'sex': '女'}\n",
      "{'id': 63, 'age': 19, 'salary': 8830, 'sex': '男'}\n",
      "{'id': 64, 'age': 28, 'salary': 8512, 'sex': '男'}\n",
      "{'id': 65, 'age': 20, 'salary': 4850, 'sex': '男'}\n",
      "{'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'id': 67, 'age': 30, 'salary': 6928, 'sex': '女'}\n",
      "{'id': 68, 'age': 29, 'salary': 3417, 'sex': '女'}\n",
      "{'id': 69, 'age': 25, 'salary': 3115, 'sex': '女'}\n",
      "{'id': 70, 'age': 23, 'salary': 2839, 'sex': '女'}\n",
      "{'id': 71, 'age': 19, 'salary': 1746, 'sex': '男'}\n",
      "{'id': 72, 'age': 18, 'salary': 1044, 'sex': '男'}\n",
      "{'id': 73, 'age': 23, 'salary': 5760, 'sex': '男'}\n",
      "{'id': 74, 'age': 23, 'salary': 3312, 'sex': '男'}\n",
      "{'id': 75, 'age': 21, 'salary': 2409, 'sex': '男'}\n",
      "{'id': 77, 'age': 16, 'salary': 2472, 'sex': '男'}\n",
      "{'id': 78, 'age': 19, 'salary': 4087, 'sex': '男'}\n",
      "{'id': 79, 'age': 29, 'salary': 3981, 'sex': '女'}\n",
      "{'id': 80, 'age': 21, 'salary': 8750, 'sex': '女'}\n",
      "{'id': 81, 'age': 19, 'salary': 2954, 'sex': '女'}\n",
      "{'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'id': 84, 'age': 20, 'salary': 2928, 'sex': '男'}\n",
      "{'id': 85, 'age': 25, 'salary': 8798, 'sex': '女'}\n",
      "{'id': 86, 'age': 19, 'salary': 4391, 'sex': '女'}\n",
      "{'id': 87, 'age': 30, 'salary': 7823, 'sex': '女'}\n",
      "{'id': 88, 'age': 22, 'salary': 2145, 'sex': '男'}\n",
      "{'id': 89, 'age': 15, 'salary': 2573, 'sex': '男'}\n",
      "{'id': 90, 'age': 20, 'salary': 3853, 'sex': '男'}\n",
      "{'id': 91, 'age': 25, 'salary': 6161, 'sex': '女'}\n",
      "{'id': 92, 'age': 15, 'salary': 7678, 'sex': '男'}\n",
      "{'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'id': 94, 'age': 26, 'salary': 1084, 'sex': '女'}\n",
      "{'id': 95, 'age': 25, 'salary': 8078, 'sex': '男'}\n",
      "{'id': 96, 'age': 17, 'salary': 2318, 'sex': '女'}\n",
      "{'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n",
      "{'id': 98, 'age': 26, 'salary': 4704, 'sex': '男'}\n",
      "{'id': 99, 'age': 17, 'salary': 6482, 'sex': '女'}\n"
     ]
    }
   ],
   "source": [
    "# OR查询，查询所有年龄大于25或者薪资小于9000的人\n",
    "\n",
    "rows = handler.find({\n",
    "    '$or': [\n",
    "        {'age': {'$gt': 25}},\n",
    "        {'salary': {'$lt': 9000}}\n",
    "        ]\n",
    "    },\n",
    "    {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'id': 22, 'age': 15, 'salary': 1930, 'sex': '女'}\n",
      "{'id': 30, 'age': 24, 'salary': 1820, 'sex': '女'}\n",
      "{'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'id': 60, 'age': 18, 'salary': 1640, 'sex': '男'}\n",
      "{'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'id': 71, 'age': 19, 'salary': 1746, 'sex': '男'}\n",
      "{'id': 72, 'age': 18, 'salary': 1044, 'sex': '男'}\n",
      "{'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'id': 94, 'age': 26, 'salary': 1084, 'sex': '女'}\n"
     ]
    }
   ],
   "source": [
    "# OR查询，查询所有年龄大于1000岁或者薪资小于2000的人，第一个条件找不到也没有关系\n",
    "\n",
    "rows = handler.find({\n",
    "    '$or': [\n",
    "        {'age': {'$gt': 1000}},\n",
    "        {'salary': {'$lt': 2000}}\n",
    "        ]\n",
    "    }, \n",
    "    {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# OR查询，查询所有年龄大于1000岁或者薪资小于0的人，所有条件都找不到才会返回空\n",
    "\n",
    "rows = handler.find({\n",
    "    '$or': [\n",
    "        {'age': {'$gt': 1000}},\n",
    "        {'salary': {'$lt': 0}}\n",
    "        ]\n",
    "    }, \n",
    "    {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 不能写成隐式AND查询的情况\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 1, 'age': 29, 'salary': 2664, 'sex': '女'}\n",
      "{'id': 14, 'age': 29, 'salary': 8825, 'sex': '女'}\n",
      "{'id': 15, 'age': 29, 'salary': 7635, 'sex': '女'}\n",
      "{'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'id': 40, 'age': 29, 'salary': 2314, 'sex': '女'}\n",
      "{'id': 52, 'age': 29, 'salary': 9868, 'sex': '男'}\n",
      "{'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'id': 58, 'age': 25, 'salary': 9975, 'sex': '男'}\n",
      "{'id': 67, 'age': 30, 'salary': 6928, 'sex': '女'}\n",
      "{'id': 68, 'age': 29, 'salary': 3417, 'sex': '女'}\n",
      "{'id': 79, 'age': 29, 'salary': 3981, 'sex': '女'}\n",
      "{'id': 87, 'age': 30, 'salary': 7823, 'sex': '女'}\n"
     ]
    }
   ],
   "source": [
    "# 首先我们搜索一下，年龄大于28岁，薪资大于9900的所有人\n",
    "\n",
    "rows = handler.find({\n",
    "    '$or': [\n",
    "        {'age': {'$gt': 28}},\n",
    "        {'salary': {'$gt': 9900}}\n",
    "        ]\n",
    "    }, \n",
    "    {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 1, 'age': 29, 'salary': 2664, 'sex': '女'}\n",
      "{'id': 14, 'age': 29, 'salary': 8825, 'sex': '女'}\n",
      "{'id': 15, 'age': 29, 'salary': 7635, 'sex': '女'}\n",
      "{'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'id': 52, 'age': 29, 'salary': 9868, 'sex': '男'}\n",
      "{'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'id': 58, 'age': 25, 'salary': 9975, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 现在，要从这一批人里面找到所有id小于20或者性别为男的人\n",
    "\n",
    "rows = handler.find(\n",
    "    {'$and': [\n",
    "        {'$or': [\n",
    "            {'age': {'$gt': 28}},\n",
    "            {'salary': {'$gt': 9900}}\n",
    "            ]\n",
    "        },\n",
    "        {'$or': [\n",
    "            {'id': {'$lt': 20}},\n",
    "            {'sex': '男'}\n",
    "            ]\n",
    "        }\n",
    "        ]\n",
    "    },\n",
    "    {'_id': 0})\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![读者交流QQ群](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-16-09-59-56.png)\n",
    "![微信公众号](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/wechatplatform.jpg)\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-20-47-47.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## MongoDB的聚合查询（一）——筛选、操作值\n",
    "\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-16-52-34.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MongoDB的聚合操作\n",
    "\n",
    "作为一个数据库，MongoDB除了基本的增删改查外，还能进行一些统计运算和数据处理。聚合查询(aggregation)就是MongoDB进行数据处理的工具之一。聚合查询是把多个不同的阶段（stage）组合在一起，从而处理数据。\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "```python\n",
    "collection.aggregate([阶段1, 阶段2, 阶段3, ..., 阶段n])\n",
    "```\n",
    "\n",
    "每一个阶段都是一个字典。一个聚合查询可以有0个、1个或者多个阶段。数据先进入第一个阶段，第一个阶段处理以后的数据进入第二个阶段，第二个阶段处理以后的数据进入第三个阶段……。\n",
    "\n",
    "#### 查询阶段\n",
    "\n",
    "```python\n",
    "{'$match': {find第一个参数}}\n",
    "```\n",
    "\n",
    "#### 修改字段\n",
    "\n",
    "```python\n",
    "{'$project': {'字段名1': 0, '字段名2': 1, ...}}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## 查询阶段"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 初始化环境\n",
    "\n",
    "import pymongo\n",
    "handler = pymongo.MongoClient().chapter_7.example_data_1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cb8'), 'id': 1, 'age': 29, 'salary': 2664, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cb9'), 'id': 2, 'age': 19, 'salary': 3086, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cba'), 'id': 3, 'age': 15, 'salary': 7662, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbb'), 'id': 4, 'age': 23, 'salary': 7001, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbc'), 'id': 5, 'age': 24, 'salary': 8042, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbd'), 'id': 6, 'age': 27, 'salary': 6847, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbe'), 'id': 7, 'age': 16, 'salary': 8916, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbf'), 'id': 8, 'age': 24, 'salary': 5191, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc0'), 'id': 9, 'age': 23, 'salary': 6643, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc1'), 'id': 10, 'age': 19, 'salary': 9775, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc2'), 'id': 11, 'age': 27, 'salary': 5931, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc3'), 'id': 12, 'age': 17, 'salary': 9582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc4'), 'id': 13, 'age': 25, 'salary': 3156, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc5'), 'id': 14, 'age': 29, 'salary': 8825, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc6'), 'id': 15, 'age': 29, 'salary': 7635, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc7'), 'id': 16, 'age': 18, 'salary': 4204, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc8'), 'id': 17, 'age': 20, 'salary': 5498, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc9'), 'id': 18, 'age': 17, 'salary': 4600, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cca'), 'id': 19, 'age': 26, 'salary': 3116, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccb'), 'id': 20, 'age': 23, 'salary': 6317, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccc'), 'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccd'), 'id': 22, 'age': 15, 'salary': 1930, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cce'), 'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccf'), 'id': 24, 'age': 27, 'salary': 8833, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd0'), 'id': 25, 'age': 15, 'salary': 2749, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd1'), 'id': 26, 'age': 28, 'salary': 2489, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd2'), 'id': 27, 'age': 21, 'salary': 3236, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd3'), 'id': 28, 'age': 27, 'salary': 7052, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd4'), 'id': 29, 'age': 26, 'salary': 7494, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd5'), 'id': 30, 'age': 24, 'salary': 1820, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd6'), 'id': 31, 'age': 17, 'salary': 9554, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd7'), 'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd8'), 'id': 33, 'age': 28, 'salary': 9276, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd9'), 'id': 34, 'age': 27, 'salary': 2931, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cda'), 'id': 35, 'age': 16, 'salary': 2443, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdb'), 'id': 36, 'age': 15, 'salary': 2073, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdc'), 'id': 37, 'age': 27, 'salary': 9361, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdd'), 'id': 38, 'age': 20, 'salary': 6039, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cde'), 'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdf'), 'id': 40, 'age': 29, 'salary': 2314, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce0'), 'id': 41, 'age': 19, 'salary': 3829, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce1'), 'id': 42, 'age': 21, 'salary': 2989, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce2'), 'id': 43, 'age': 18, 'salary': 3813, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce3'), 'id': 44, 'age': 22, 'salary': 6060, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce4'), 'id': 45, 'age': 25, 'salary': 5602, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce5'), 'id': 46, 'age': 18, 'salary': 7582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce6'), 'id': 47, 'age': 27, 'salary': 8937, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce7'), 'id': 48, 'age': 21, 'salary': 4565, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce8'), 'id': 49, 'age': 26, 'salary': 6087, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce9'), 'id': 50, 'age': 23, 'salary': 4103, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cea'), 'id': 51, 'age': 19, 'salary': 2733, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ceb'), 'id': 52, 'age': 29, 'salary': 9868, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cec'), 'id': 53, 'age': 24, 'salary': 8977, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ced'), 'id': 54, 'age': 25, 'salary': 6052, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cee'), 'id': 55, 'age': 23, 'salary': 3741, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cef'), 'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf0'), 'id': 57, 'age': 26, 'salary': 4691, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf1'), 'id': 58, 'age': 25, 'salary': 9975, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf2'), 'id': 59, 'age': 16, 'salary': 9699, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf3'), 'id': 60, 'age': 18, 'salary': 1640, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf4'), 'id': 61, 'age': 28, 'salary': 7494, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf5'), 'id': 62, 'age': 22, 'salary': 9420, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf6'), 'id': 63, 'age': 19, 'salary': 8830, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf7'), 'id': 64, 'age': 28, 'salary': 8512, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf8'), 'id': 65, 'age': 20, 'salary': 4850, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf9'), 'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfa'), 'id': 67, 'age': 30, 'salary': 6928, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfb'), 'id': 68, 'age': 29, 'salary': 3417, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfc'), 'id': 69, 'age': 25, 'salary': 3115, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfd'), 'id': 70, 'age': 23, 'salary': 2839, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfe'), 'id': 71, 'age': 19, 'salary': 1746, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cff'), 'id': 72, 'age': 18, 'salary': 1044, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d00'), 'id': 73, 'age': 23, 'salary': 5760, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d01'), 'id': 74, 'age': 23, 'salary': 3312, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d02'), 'id': 75, 'age': 21, 'salary': 2409, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d03'), 'id': 76, 'age': 20, 'salary': 9164, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d04'), 'id': 77, 'age': 16, 'salary': 2472, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d05'), 'id': 78, 'age': 19, 'salary': 4087, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d06'), 'id': 79, 'age': 29, 'salary': 3981, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d07'), 'id': 80, 'age': 21, 'salary': 8750, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d08'), 'id': 81, 'age': 19, 'salary': 2954, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d09'), 'id': 82, 'age': 21, 'salary': 9409, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0a'), 'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0b'), 'id': 84, 'age': 20, 'salary': 2928, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0c'), 'id': 85, 'age': 25, 'salary': 8798, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0d'), 'id': 86, 'age': 19, 'salary': 4391, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0e'), 'id': 87, 'age': 30, 'salary': 7823, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0f'), 'id': 88, 'age': 22, 'salary': 2145, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d10'), 'id': 89, 'age': 15, 'salary': 2573, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d11'), 'id': 90, 'age': 20, 'salary': 3853, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d12'), 'id': 91, 'age': 25, 'salary': 6161, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d13'), 'id': 92, 'age': 15, 'salary': 7678, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d14'), 'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d15'), 'id': 94, 'age': 26, 'salary': 1084, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d16'), 'id': 95, 'age': 25, 'salary': 8078, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d17'), 'id': 96, 'age': 17, 'salary': 2318, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d18'), 'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d19'), 'id': 98, 'age': 26, 'salary': 4704, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d1a'), 'id': 99, 'age': 17, 'salary': 6482, 'sex': '女'}\n"
     ]
    }
   ],
   "source": [
    "# 没有阶段的聚合查询\n",
    "\n",
    "rows = handler.aggregate([])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cb8'), 'id': 1, 'age': 29, 'salary': 2664, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cb9'), 'id': 2, 'age': 19, 'salary': 3086, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cba'), 'id': 3, 'age': 15, 'salary': 7662, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbb'), 'id': 4, 'age': 23, 'salary': 7001, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbc'), 'id': 5, 'age': 24, 'salary': 8042, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbd'), 'id': 6, 'age': 27, 'salary': 6847, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbe'), 'id': 7, 'age': 16, 'salary': 8916, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbf'), 'id': 8, 'age': 24, 'salary': 5191, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc0'), 'id': 9, 'age': 23, 'salary': 6643, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc1'), 'id': 10, 'age': 19, 'salary': 9775, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc2'), 'id': 11, 'age': 27, 'salary': 5931, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc3'), 'id': 12, 'age': 17, 'salary': 9582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc4'), 'id': 13, 'age': 25, 'salary': 3156, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc5'), 'id': 14, 'age': 29, 'salary': 8825, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc6'), 'id': 15, 'age': 29, 'salary': 7635, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc7'), 'id': 16, 'age': 18, 'salary': 4204, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc8'), 'id': 17, 'age': 20, 'salary': 5498, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc9'), 'id': 18, 'age': 17, 'salary': 4600, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cca'), 'id': 19, 'age': 26, 'salary': 3116, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccb'), 'id': 20, 'age': 23, 'salary': 6317, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccc'), 'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccd'), 'id': 22, 'age': 15, 'salary': 1930, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cce'), 'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccf'), 'id': 24, 'age': 27, 'salary': 8833, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd0'), 'id': 25, 'age': 15, 'salary': 2749, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd1'), 'id': 26, 'age': 28, 'salary': 2489, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd2'), 'id': 27, 'age': 21, 'salary': 3236, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd3'), 'id': 28, 'age': 27, 'salary': 7052, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd4'), 'id': 29, 'age': 26, 'salary': 7494, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd5'), 'id': 30, 'age': 24, 'salary': 1820, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd6'), 'id': 31, 'age': 17, 'salary': 9554, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd7'), 'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd8'), 'id': 33, 'age': 28, 'salary': 9276, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd9'), 'id': 34, 'age': 27, 'salary': 2931, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cda'), 'id': 35, 'age': 16, 'salary': 2443, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdb'), 'id': 36, 'age': 15, 'salary': 2073, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdc'), 'id': 37, 'age': 27, 'salary': 9361, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdd'), 'id': 38, 'age': 20, 'salary': 6039, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cde'), 'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdf'), 'id': 40, 'age': 29, 'salary': 2314, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce0'), 'id': 41, 'age': 19, 'salary': 3829, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce1'), 'id': 42, 'age': 21, 'salary': 2989, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce2'), 'id': 43, 'age': 18, 'salary': 3813, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce3'), 'id': 44, 'age': 22, 'salary': 6060, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce4'), 'id': 45, 'age': 25, 'salary': 5602, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce5'), 'id': 46, 'age': 18, 'salary': 7582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce6'), 'id': 47, 'age': 27, 'salary': 8937, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce7'), 'id': 48, 'age': 21, 'salary': 4565, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce8'), 'id': 49, 'age': 26, 'salary': 6087, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce9'), 'id': 50, 'age': 23, 'salary': 4103, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cea'), 'id': 51, 'age': 19, 'salary': 2733, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ceb'), 'id': 52, 'age': 29, 'salary': 9868, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cec'), 'id': 53, 'age': 24, 'salary': 8977, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ced'), 'id': 54, 'age': 25, 'salary': 6052, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cee'), 'id': 55, 'age': 23, 'salary': 3741, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cef'), 'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf0'), 'id': 57, 'age': 26, 'salary': 4691, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf1'), 'id': 58, 'age': 25, 'salary': 9975, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf2'), 'id': 59, 'age': 16, 'salary': 9699, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf3'), 'id': 60, 'age': 18, 'salary': 1640, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf4'), 'id': 61, 'age': 28, 'salary': 7494, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf5'), 'id': 62, 'age': 22, 'salary': 9420, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf6'), 'id': 63, 'age': 19, 'salary': 8830, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf7'), 'id': 64, 'age': 28, 'salary': 8512, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf8'), 'id': 65, 'age': 20, 'salary': 4850, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf9'), 'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfa'), 'id': 67, 'age': 30, 'salary': 6928, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfb'), 'id': 68, 'age': 29, 'salary': 3417, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfc'), 'id': 69, 'age': 25, 'salary': 3115, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfd'), 'id': 70, 'age': 23, 'salary': 2839, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfe'), 'id': 71, 'age': 19, 'salary': 1746, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cff'), 'id': 72, 'age': 18, 'salary': 1044, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d00'), 'id': 73, 'age': 23, 'salary': 5760, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d01'), 'id': 74, 'age': 23, 'salary': 3312, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d02'), 'id': 75, 'age': 21, 'salary': 2409, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d03'), 'id': 76, 'age': 20, 'salary': 9164, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d04'), 'id': 77, 'age': 16, 'salary': 2472, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d05'), 'id': 78, 'age': 19, 'salary': 4087, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d06'), 'id': 79, 'age': 29, 'salary': 3981, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d07'), 'id': 80, 'age': 21, 'salary': 8750, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d08'), 'id': 81, 'age': 19, 'salary': 2954, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d09'), 'id': 82, 'age': 21, 'salary': 9409, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0a'), 'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0b'), 'id': 84, 'age': 20, 'salary': 2928, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0c'), 'id': 85, 'age': 25, 'salary': 8798, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0d'), 'id': 86, 'age': 19, 'salary': 4391, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0e'), 'id': 87, 'age': 30, 'salary': 7823, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0f'), 'id': 88, 'age': 22, 'salary': 2145, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d10'), 'id': 89, 'age': 15, 'salary': 2573, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d11'), 'id': 90, 'age': 20, 'salary': 3853, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d12'), 'id': 91, 'age': 25, 'salary': 6161, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d13'), 'id': 92, 'age': 15, 'salary': 7678, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d14'), 'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d15'), 'id': 94, 'age': 26, 'salary': 1084, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d16'), 'id': 95, 'age': 25, 'salary': 8078, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d17'), 'id': 96, 'age': 17, 'salary': 2318, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d18'), 'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d19'), 'id': 98, 'age': 26, 'salary': 4704, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d1a'), 'id': 99, 'age': 17, 'salary': 6482, 'sex': '女'}\n"
     ]
    }
   ],
   "source": [
    "# 使用find查询数据\n",
    "\n",
    "rows = handler.find()\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cb9'), 'id': 2, 'age': 19, 'salary': 3086, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbd'), 'id': 6, 'age': 27, 'salary': 6847, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbe'), 'id': 7, 'age': 16, 'salary': 8916, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc0'), 'id': 9, 'age': 23, 'salary': 6643, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc2'), 'id': 11, 'age': 27, 'salary': 5931, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc4'), 'id': 13, 'age': 25, 'salary': 3156, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc8'), 'id': 17, 'age': 20, 'salary': 5498, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc9'), 'id': 18, 'age': 17, 'salary': 4600, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccb'), 'id': 20, 'age': 23, 'salary': 6317, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccc'), 'id': 21, 'age': 26, 'salary': 1583, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cce'), 'id': 23, 'age': 29, 'salary': 5977, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd0'), 'id': 25, 'age': 15, 'salary': 2749, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd1'), 'id': 26, 'age': 28, 'salary': 2489, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd2'), 'id': 27, 'age': 21, 'salary': 3236, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd6'), 'id': 31, 'age': 17, 'salary': 9554, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd7'), 'id': 32, 'age': 27, 'salary': 1668, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd8'), 'id': 33, 'age': 28, 'salary': 9276, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd9'), 'id': 34, 'age': 27, 'salary': 2931, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cda'), 'id': 35, 'age': 16, 'salary': 2443, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdc'), 'id': 37, 'age': 27, 'salary': 9361, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cde'), 'id': 39, 'age': 29, 'salary': 6671, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce0'), 'id': 41, 'age': 19, 'salary': 3829, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce2'), 'id': 43, 'age': 18, 'salary': 3813, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce7'), 'id': 48, 'age': 21, 'salary': 4565, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce9'), 'id': 50, 'age': 23, 'salary': 4103, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cea'), 'id': 51, 'age': 19, 'salary': 2733, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ceb'), 'id': 52, 'age': 29, 'salary': 9868, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cee'), 'id': 55, 'age': 23, 'salary': 3741, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cef'), 'id': 56, 'age': 30, 'salary': 2385, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf0'), 'id': 57, 'age': 26, 'salary': 4691, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf1'), 'id': 58, 'age': 25, 'salary': 9975, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf2'), 'id': 59, 'age': 16, 'salary': 9699, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf3'), 'id': 60, 'age': 18, 'salary': 1640, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf5'), 'id': 62, 'age': 22, 'salary': 9420, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf6'), 'id': 63, 'age': 19, 'salary': 8830, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf7'), 'id': 64, 'age': 28, 'salary': 8512, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf8'), 'id': 65, 'age': 20, 'salary': 4850, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf9'), 'id': 66, 'age': 27, 'salary': 1286, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfe'), 'id': 71, 'age': 19, 'salary': 1746, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cff'), 'id': 72, 'age': 18, 'salary': 1044, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d00'), 'id': 73, 'age': 23, 'salary': 5760, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d01'), 'id': 74, 'age': 23, 'salary': 3312, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d02'), 'id': 75, 'age': 21, 'salary': 2409, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d04'), 'id': 77, 'age': 16, 'salary': 2472, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d05'), 'id': 78, 'age': 19, 'salary': 4087, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0a'), 'id': 83, 'age': 28, 'salary': 1189, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0b'), 'id': 84, 'age': 20, 'salary': 2928, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0f'), 'id': 88, 'age': 22, 'salary': 2145, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d10'), 'id': 89, 'age': 15, 'salary': 2573, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d11'), 'id': 90, 'age': 20, 'salary': 3853, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d13'), 'id': 92, 'age': 15, 'salary': 7678, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d14'), 'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d16'), 'id': 95, 'age': 25, 'salary': 8078, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d18'), 'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d19'), 'id': 98, 'age': 26, 'salary': 4704, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 查询所有性别为男的数据\n",
    "\n",
    "rows = handler.aggregate([{'$match': {'sex': '男'}}])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cba'), 'id': 3, 'age': 15, 'salary': 7662, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbb'), 'id': 4, 'age': 23, 'salary': 7001, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbc'), 'id': 5, 'age': 24, 'salary': 8042, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbf'), 'id': 8, 'age': 24, 'salary': 5191, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc1'), 'id': 10, 'age': 19, 'salary': 9775, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc3'), 'id': 12, 'age': 17, 'salary': 9582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc7'), 'id': 16, 'age': 18, 'salary': 4204, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccd'), 'id': 22, 'age': 15, 'salary': 1930, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd5'), 'id': 30, 'age': 24, 'salary': 1820, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdb'), 'id': 36, 'age': 15, 'salary': 2073, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdd'), 'id': 38, 'age': 20, 'salary': 6039, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce1'), 'id': 42, 'age': 21, 'salary': 2989, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce3'), 'id': 44, 'age': 22, 'salary': 6060, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce5'), 'id': 46, 'age': 18, 'salary': 7582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cec'), 'id': 53, 'age': 24, 'salary': 8977, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfd'), 'id': 70, 'age': 23, 'salary': 2839, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d03'), 'id': 76, 'age': 20, 'salary': 9164, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d07'), 'id': 80, 'age': 21, 'salary': 8750, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d08'), 'id': 81, 'age': 19, 'salary': 2954, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d09'), 'id': 82, 'age': 21, 'salary': 9409, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0d'), 'id': 86, 'age': 19, 'salary': 4391, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d17'), 'id': 96, 'age': 17, 'salary': 2318, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d1a'), 'id': 99, 'age': 17, 'salary': 6482, 'sex': '女'}\n"
     ]
    }
   ],
   "source": [
    "# 查询所有性别为女并且age小于25的数据\n",
    "\n",
    "rows = handler.aggregate([{'$match': {'sex': '女', 'age': {'$lt': 25}}}])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cb9'), 'id': 2, 'age': 19, 'salary': 3086, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cba'), 'id': 3, 'age': 15, 'salary': 7662, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbb'), 'id': 4, 'age': 23, 'salary': 7001, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbc'), 'id': 5, 'age': 24, 'salary': 8042, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbe'), 'id': 7, 'age': 16, 'salary': 8916, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbf'), 'id': 8, 'age': 24, 'salary': 5191, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc1'), 'id': 10, 'age': 19, 'salary': 9775, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc3'), 'id': 12, 'age': 17, 'salary': 9582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc7'), 'id': 16, 'age': 18, 'salary': 4204, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc9'), 'id': 18, 'age': 17, 'salary': 4600, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ccd'), 'id': 22, 'age': 15, 'salary': 1930, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd0'), 'id': 25, 'age': 15, 'salary': 2749, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd5'), 'id': 30, 'age': 24, 'salary': 1820, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd6'), 'id': 31, 'age': 17, 'salary': 9554, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cda'), 'id': 35, 'age': 16, 'salary': 2443, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdb'), 'id': 36, 'age': 15, 'salary': 2073, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cdd'), 'id': 38, 'age': 20, 'salary': 6039, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce0'), 'id': 41, 'age': 19, 'salary': 3829, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce1'), 'id': 42, 'age': 21, 'salary': 2989, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce2'), 'id': 43, 'age': 18, 'salary': 3813, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce3'), 'id': 44, 'age': 22, 'salary': 6060, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce5'), 'id': 46, 'age': 18, 'salary': 7582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cea'), 'id': 51, 'age': 19, 'salary': 2733, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cec'), 'id': 53, 'age': 24, 'salary': 8977, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf2'), 'id': 59, 'age': 16, 'salary': 9699, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf3'), 'id': 60, 'age': 18, 'salary': 1640, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf6'), 'id': 63, 'age': 19, 'salary': 8830, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfd'), 'id': 70, 'age': 23, 'salary': 2839, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cfe'), 'id': 71, 'age': 19, 'salary': 1746, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cff'), 'id': 72, 'age': 18, 'salary': 1044, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d03'), 'id': 76, 'age': 20, 'salary': 9164, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d04'), 'id': 77, 'age': 16, 'salary': 2472, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d05'), 'id': 78, 'age': 19, 'salary': 4087, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d07'), 'id': 80, 'age': 21, 'salary': 8750, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d08'), 'id': 81, 'age': 19, 'salary': 2954, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d09'), 'id': 82, 'age': 21, 'salary': 9409, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0d'), 'id': 86, 'age': 19, 'salary': 4391, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d10'), 'id': 89, 'age': 15, 'salary': 2573, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d13'), 'id': 92, 'age': 15, 'salary': 7678, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d17'), 'id': 96, 'age': 17, 'salary': 2318, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d1a'), 'id': 99, 'age': 17, 'salary': 6482, 'sex': '女'}\n"
     ]
    }
   ],
   "source": [
    "# 查询所有（性别为女并且age小于25）或者（性别为男，age小于20）的数据\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {\n",
    "        '$or': [\n",
    "            {'sex': '女', 'age': {'$lt': 25}},\n",
    "            {'sex': '男', 'age': {'$lt': 20}}\n",
    "        ]\n",
    "    }}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 修改或者限定返回字段\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cba'), 'id': 3, 'age': 15, 'salary': 7662, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbb'), 'id': 4, 'age': 23, 'salary': 7001, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc6'), 'id': 15, 'age': 29, 'salary': 7635, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd3'), 'id': 28, 'age': 27, 'salary': 7052, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd4'), 'id': 29, 'age': 26, 'salary': 7494, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce5'), 'id': 46, 'age': 18, 'salary': 7582, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf4'), 'id': 61, 'age': 28, 'salary': 7494, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0e'), 'id': 87, 'age': 30, 'salary': 7823, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d13'), 'id': 92, 'age': 15, 'salary': 7678, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d14'), 'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d18'), 'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 查询所有7000 < salary < 8000的数据\n",
    "\n",
    "rows = handler.aggregate([{'$match': {'salary': {'$lt': 8000, '$gt': 7000}}}])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 3, 'age': 15, 'salary': 7662, 'sex': '女'}\n",
      "{'id': 4, 'age': 23, 'salary': 7001, 'sex': '女'}\n",
      "{'id': 15, 'age': 29, 'salary': 7635, 'sex': '女'}\n",
      "{'id': 28, 'age': 27, 'salary': 7052, 'sex': '女'}\n",
      "{'id': 29, 'age': 26, 'salary': 7494, 'sex': '女'}\n",
      "{'id': 46, 'age': 18, 'salary': 7582, 'sex': '女'}\n",
      "{'id': 61, 'age': 28, 'salary': 7494, 'sex': '女'}\n",
      "{'id': 87, 'age': 30, 'salary': 7823, 'sex': '女'}\n",
      "{'id': 92, 'age': 15, 'salary': 7678, 'sex': '男'}\n",
      "{'id': 93, 'age': 27, 'salary': 7228, 'sex': '男'}\n",
      "{'id': 97, 'age': 26, 'salary': 7811, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 不返回_id\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {'salary': {'$lt': 8000, '$gt': 7000}}},\n",
    "    {'$project': {'_id': 0}}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cba'), 'id': 3, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cbb'), 'id': 4, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cc6'), 'id': 15, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd3'), 'id': 28, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cd4'), 'id': 29, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676ce5'), 'id': 46, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676cf4'), 'id': 61, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d0e'), 'id': 87, 'sex': '女'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d13'), 'id': 92, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d14'), 'id': 93, 'sex': '男'}\n",
      "{'_id': ObjectId('5b0ab1a46b78a66b9a676d18'), 'id': 97, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 只返回id和sex，不显式删除_id\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {'salary': {'$lt': 8000, '$gt': 7000}}},\n",
    "    {'$project': {'id': 1, 'sex': 1}}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 3, 'sex': '女'}\n",
      "{'id': 4, 'sex': '女'}\n",
      "{'id': 15, 'sex': '女'}\n",
      "{'id': 28, 'sex': '女'}\n",
      "{'id': 29, 'sex': '女'}\n",
      "{'id': 46, 'sex': '女'}\n",
      "{'id': 61, 'sex': '女'}\n",
      "{'id': 87, 'sex': '女'}\n",
      "{'id': 92, 'sex': '男'}\n",
      "{'id': 93, 'sex': '男'}\n",
      "{'id': 97, 'sex': '男'}\n"
     ]
    }
   ],
   "source": [
    "# 只返回id和sex，显式删除_id\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {'salary': {'$lt': 8000, '$gt': 7000}}},\n",
    "    {'$project': {'_id': 0, 'id': 1, 'sex': 1}}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "ename": "OperationFailure",
     "evalue": "Bad projection specification, cannot include fields or add computed fields during an exclusion projection: { salary: 0, id: 1, sex: 1 }",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mOperationFailure\u001b[0m                          Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-39-129bfaee4f4a>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      3\u001b[0m rows = handler.aggregate([\n\u001b[1;32m      4\u001b[0m     \u001b[0;34m{\u001b[0m\u001b[0;34m'$match'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m'salary'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m'$lt'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m8000\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'$gt'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m7000\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m     \u001b[0;34m{\u001b[0m\u001b[0;34m'$project'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m{\u001b[0m\u001b[0;34m'salary'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'id'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'sex'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;36m1\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m}\u001b[0m   \u001b[0;31m# 这里必定报错\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      6\u001b[0m ])\n\u001b[1;32m      7\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mrow\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrows\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/collection.py\u001b[0m in \u001b[0;36maggregate\u001b[0;34m(self, pipeline, **kwargs)\u001b[0m\n\u001b[1;32m   1868\u001b[0m                     result = self._command(sock_info, cmd, slave_ok,\n\u001b[1;32m   1869\u001b[0m                                            \u001b[0mread_concern\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_concern\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1870\u001b[0;31m                                            collation=collation)\n\u001b[0m\u001b[1;32m   1871\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1872\u001b[0m                 result = self._command(sock_info, cmd, slave_ok,\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/collection.py\u001b[0m in \u001b[0;36m_command\u001b[0;34m(self, sock_info, command, slave_ok, read_preference, codec_options, check, allowable_errors, read_concern, write_concern, parse_write_concern_error, collation)\u001b[0m\n\u001b[1;32m    230\u001b[0m             \u001b[0mwrite_concern\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwrite_concern\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    231\u001b[0m             \u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 232\u001b[0;31m             collation=collation)\n\u001b[0m\u001b[1;32m    233\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    234\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__create\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moptions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollation\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/pool.py\u001b[0m in \u001b[0;36mcommand\u001b[0;34m(self, dbname, spec, slave_ok, read_preference, codec_options, check, allowable_errors, check_keys, read_concern, write_concern, parse_write_concern_error, collation)\u001b[0m\n\u001b[1;32m    417\u001b[0m                            \u001b[0mread_concern\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    418\u001b[0m                            \u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 419\u001b[0;31m                            collation=collation)\n\u001b[0m\u001b[1;32m    420\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mOperationFailure\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    421\u001b[0m             \u001b[0;32mraise\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/network.py\u001b[0m in \u001b[0;36mcommand\u001b[0;34m(sock, dbname, spec, slave_ok, is_mongos, read_preference, codec_options, check, allowable_errors, address, check_keys, listeners, max_bson_size, read_concern, parse_write_concern_error, collation)\u001b[0m\n\u001b[1;32m    114\u001b[0m             helpers._check_command_response(\n\u001b[1;32m    115\u001b[0m                 \u001b[0mresponse_doc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mallowable_errors\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 116\u001b[0;31m                 parse_write_concern_error=parse_write_concern_error)\n\u001b[0m\u001b[1;32m    117\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mexc\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    118\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mpublish\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/helpers.py\u001b[0m in \u001b[0;36m_check_command_response\u001b[0;34m(response, msg, allowable_errors, parse_write_concern_error)\u001b[0m\n\u001b[1;32m    208\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    209\u001b[0m             \u001b[0mmsg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmsg\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m\"%s\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 210\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mOperationFailure\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0merrmsg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    211\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    212\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mOperationFailure\u001b[0m: Bad projection specification, cannot include fields or add computed fields during an exclusion projection: { salary: 0, id: 1, sex: 1 }"
     ]
    }
   ],
   "source": [
    "# 除了_id外，其他的元素只能同时指定不显示，或者同时指定显示，不能0和1混用，否则必定报错\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {'salary': {'$lt': 8000, '$gt': 7000}}},\n",
    "    {'$project': {'salary': 0, 'id': 1, 'sex': 1}}   # 这里必定报错\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 3, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 4, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 15, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 28, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 29, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 46, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 61, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 87, 'sex': '女', 'hello': 'word'}\n",
      "{'id': 92, 'sex': '男', 'hello': 'word'}\n",
      "{'id': 93, 'sex': '男', 'hello': 'word'}\n",
      "{'id': 97, 'sex': '男', 'hello': 'word'}\n"
     ]
    }
   ],
   "source": [
    "# 增加新的字段\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {'salary': {'$lt': 8000, '$gt': 7000}}},\n",
    "    {'$project': {'_id': 0, 'id': 1, 'sex': 1, 'hello': 'word'}}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 3, 'sex': '女', '月薪': 7662}\n",
      "{'id': 4, 'sex': '女', '月薪': 7001}\n",
      "{'id': 15, 'sex': '女', '月薪': 7635}\n",
      "{'id': 28, 'sex': '女', '月薪': 7052}\n",
      "{'id': 29, 'sex': '女', '月薪': 7494}\n",
      "{'id': 46, 'sex': '女', '月薪': 7582}\n",
      "{'id': 61, 'sex': '女', '月薪': 7494}\n",
      "{'id': 87, 'sex': '女', '月薪': 7823}\n",
      "{'id': 92, 'sex': '男', '月薪': 7678}\n",
      "{'id': 93, 'sex': '男', '月薪': 7228}\n",
      "{'id': 97, 'sex': '男', '月薪': 7811}\n"
     ]
    }
   ],
   "source": [
    "# 复制已有字段\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {'salary': {'$lt': 8000, '$gt': 7000}}},\n",
    "    {'$project': {'_id': 0, 'id': 1, 'sex': 1, '月薪': '$salary'}}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'id': 3, 'sex': '保密'}\n",
      "{'id': 4, 'sex': '保密'}\n",
      "{'id': 15, 'sex': '保密'}\n",
      "{'id': 28, 'sex': '保密'}\n",
      "{'id': 29, 'sex': '保密'}\n",
      "{'id': 46, 'sex': '保密'}\n",
      "{'id': 61, 'sex': '保密'}\n",
      "{'id': 87, 'sex': '保密'}\n",
      "{'id': 92, 'sex': '保密'}\n",
      "{'id': 93, 'sex': '保密'}\n",
      "{'id': 97, 'sex': '保密'}\n"
     ]
    }
   ],
   "source": [
    "# 覆盖现有字段\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$match': {'salary': {'$lt': 8000, '$gt': 7000}}},\n",
    "    {'$project': {'_id': 0, 'id': 1, 'sex': '保密'}}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b13a1b06b78a643182f8ac4'), 'content': '这道菜真好吃', 'create_time': '2018-06-01', 'user': {'name': '青南', 'user_id': 101, 'following': 1, 'followed': 9999}, 'comments': 100}\n",
      "{'_id': ObjectId('5b13a1b06b78a643182f8ac5'), 'content': '儿童节快乐', 'create_time': '2018-06-01', 'user': {'name': '小盆友', 'user_id': 102, 'following': 99, 'followed': 3}, 'comments': 1}\n",
      "{'_id': ObjectId('5b13a1b06b78a643182f8ac6'), 'content': '我的礼物在哪里？', 'create_time': '2018-05-30', 'user': {'name': '学习鸡', 'user_id': 103, 'following': 45, 'followed': 20}, 'comments': 20}\n",
      "{'_id': ObjectId('5b13a1b06b78a643182f8ac7'), 'content': '求勾搭', 'create_time': '2018-05-20', 'user': {'name': '单身的小X', 'user_id': 104, 'following': 8888, 'followed': 0}, 'comments': 0}\n"
     ]
    }
   ],
   "source": [
    "# 包含嵌套字段的数据\n",
    "handler2 = pymongo.MongoClient().chapter_7.example_data_2\n",
    "rows = handler2.find()\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "青南\n",
      "小盆友\n",
      "学习鸡\n",
      "单身的小X\n"
     ]
    }
   ],
   "source": [
    "# 普通方法读取嵌套字段中的name\n",
    "\n",
    "rows = handler2.find()\n",
    "for row in rows:\n",
    "    print(row['user']['name'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'content': '这道菜真好吃', 'name': '青南'}\n",
      "{'content': '儿童节快乐', 'name': '小盆友'}\n",
      "{'content': '我的礼物在哪里？', 'name': '学习鸡'}\n",
      "{'content': '求勾搭', 'name': '单身的小X'}\n"
     ]
    }
   ],
   "source": [
    "# 使用$project抽出嵌套字段\n",
    "\n",
    "rows = handler2.aggregate([\n",
    "    {'$project': {'content': 1, '_id': 0, 'name': '$user.name'}}\n",
    "])\n",
    "\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'content': '这道菜真好吃', 'name': '青南'}\n",
      "{'content': '儿童节快乐', 'name': '小盆友'}\n",
      "{'content': '我的礼物在哪里？', 'name': '学习鸡'}\n",
      "{'content': '求勾搭', 'name': '单身的小X'}\n"
     ]
    }
   ],
   "source": [
    "# 以$开头的特殊值无法正常显示，值本身就是数字的也无法正常显示\n",
    "\n",
    "rows = handler2.aggregate([\n",
    "    {'$project': {'content': 1, '_id': 0, 'name': '$user.name', 'new': '$我是特殊值'}}\n",
    "])\n",
    "\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'content': '这道菜真好吃', 'name': '青南', 'new': '$我是特殊值', 'num_1': 1, 'num_0': 0}\n",
      "{'content': '儿童节快乐', 'name': '小盆友', 'new': '$我是特殊值', 'num_1': 1, 'num_0': 0}\n",
      "{'content': '我的礼物在哪里？', 'name': '学习鸡', 'new': '$我是特殊值', 'num_1': 1, 'num_0': 0}\n",
      "{'content': '求勾搭', 'name': '单身的小X', 'new': '$我是特殊值', 'num_1': 1, 'num_0': 0}\n"
     ]
    }
   ],
   "source": [
    "# 使得以$开头的特殊值可以正常显示\n",
    "\n",
    "rows = handler2.aggregate([\n",
    "    {'$project': {'content': 1,\n",
    "                  '_id': 0,\n",
    "                  'name': '$user.name',\n",
    "                  'new': {'$literal': '$我是特殊值'},\n",
    "                  'num_1': {'$literal': 1},\n",
    "                  'num_0': {'$literal': 0}\n",
    "                 }\n",
    "    }\n",
    "])\n",
    "\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![读者交流QQ群](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-16-09-59-56.png)\n",
    "![微信公众号](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/wechatplatform.jpg)\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-20-47-47.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## MongoDB的聚合查询（二）——分组查询\n",
    "\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-16-52-34.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MongoDB的聚合操作\n",
    "\n",
    "作为一个数据库，MongoDB除了基本的增删改查外，还能进行一些统计运算和数据处理。聚合查询(aggregation)就是MongoDB进行数据处理的工具之一。聚合查询是把多个不同的阶段（stage）组合在一起，从而处理数据。\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "```python\n",
    "collection.aggregate([阶段1, 阶段2, 阶段3, ..., 阶段n])\n",
    "```\n",
    "\n",
    "每一个阶段都是一个字典。一个聚合查询可以有0个、1个或者多个阶段。数据先进入第一个阶段，第一个阶段处理以后的数据进入第二个阶段，第二个阶段处理以后的数据进入第三个阶段……。\n",
    "\n",
    "#### 分组操作\n",
    "\n",
    "```python\n",
    "{'$group': {'_id': '$被去重的字段名'}}\n",
    "{'$group': {'_id': '$被去重的字段名', '最大值': {'$max': '$字段名'}, '最小值': {'$min': '$字段名'}}}\n",
    "{'$group': {'_id': '$被去重的字段名', '平均值': {'$avg': '$字段名'}, '求和': {'$sum': '$字段名'}}}\n",
    "{'$group': {'_id': '$被去重的字段名', '计数': {'$sum': 1}}}\n",
    "{'$group': {'_id': '$被去重的字段名', '最新值': {'$last': '$字段名'}, '最旧值': {'$last': '$字段名'}}}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 连接数据库\n",
    "\n",
    "import pymongo\n",
    "handler = pymongo.MongoClient().chapter_7.example_data_4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 替代 distinct"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['张三', '李四', '王五']"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "handler.distinct('name')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<pymongo.command_cursor.CommandCursor object at 0x10ca6f748>\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[{'_id': '王五'}, {'_id': '李四'}, {'_id': '张三'}]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = handler.aggregate([\n",
    "    {'$group': {'_id': '$name'}}\n",
    "])\n",
    "print(rows)\n",
    "\n",
    "list(rows)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'_id': 'name'}]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果name 字段不加美元符号会怎么样\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$group': {'_id': 'name'}}\n",
    "])\n",
    "list(rows)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 增加计算统计值\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'_id': '王五', '平均分': 73.4, '总分': 367, '最大分': 78, '最小分': 66},\n",
       " {'_id': '李四', '平均分': 75.33333333333333, '总分': 452, '最大分': 81, '最小分': 66},\n",
       " {'_id': '张三', '平均分': 74.8, '总分': 374, '最大分': 82, '最小分': 65}]"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = handler.aggregate([\n",
    "    {'$group': {'_id': '$name',\n",
    "                '平均分': {'$avg': '$score'},\n",
    "                '最大分': {'$max': '$score'},\n",
    "                '最小分': {'$min': '$score'},\n",
    "                '总分': {'$sum': '$score'}}}\n",
    "])\n",
    "list(rows)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'_id': '王五', '平均分': None, '总分': 0, '最大分': 'score', '最小分': 'score'},\n",
       " {'_id': '李四', '平均分': None, '总分': 0, '最大分': 'score', '最小分': 'score'},\n",
       " {'_id': '张三', '平均分': None, '总分': 0, '最大分': 'score', '最小分': 'score'}]"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 如果score 字段不加美元符号会怎么样？\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$group': {'_id': '$name',\n",
    "                '平均分': {'$avg': 'score'},\n",
    "                '最大分': {'$max': 'score'},\n",
    "                '最小分': {'$min': 'score'},\n",
    "                '总分': {'$sum': 'score'}}}\n",
    "])\n",
    "list(rows)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 计数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'_id': '王五', '计数': 5}, {'_id': '李四', '计数': 6}, {'_id': '张三', '计数': 5}]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = handler.aggregate([\n",
    "    {'$group': {'_id': '$name',\n",
    "                '计数': {'$sum': 1},\n",
    "                }}\n",
    "])\n",
    "list(rows)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 去重并保留字段"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'_id': '王五', 'date': '2018-06-10', 'score': 78},\n",
       " {'_id': '李四', 'date': '2018-06-10', 'score': 81},\n",
       " {'_id': '张三', 'date': '2018-06-07', 'score': 82}]"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = handler.aggregate([\n",
    "    {'$group': {'_id': '$name',\n",
    "                'date': {'$last': '$date'},\n",
    "                'score': {'$last': '$score'}\n",
    "                }}\n",
    "])\n",
    "list(rows)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'_id': '王五', 'date': '2018-06-01', 'score': 66},\n",
       " {'_id': '李四', 'date': '2018-06-01', 'score': 66},\n",
       " {'_id': '张三', 'date': '2018-06-01', 'score': 65}]"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rows = handler.aggregate([\n",
    "    {'$group': {'_id': '$name',\n",
    "                'date': {'$first': '$date'},\n",
    "                'score': {'$first': '$score'}\n",
    "                }}\n",
    "])\n",
    "list(rows)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![读者交流QQ群](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-16-09-59-56.png)\n",
    "![微信公众号](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/wechatplatform.jpg)\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-20-47-47.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## MongoDB的聚合查询（三）——拆分数组\n",
    "\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-16-52-34.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## MongoDB的聚合操作\n",
    "\n",
    "作为一个数据库，MongoDB除了基本的增删改查外，还能进行一些统计运算和数据处理。聚合查询(aggregation)就是MongoDB进行数据处理的工具之一。聚合查询是把多个不同的阶段（stage）组合在一起，从而处理数据。\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "```python\n",
    "collection.aggregate([阶段1, 阶段2, 阶段3, ..., 阶段n])\n",
    "```\n",
    "\n",
    "每一个阶段都是一个字典。一个聚合查询可以有0个、1个或者多个阶段。数据先进入第一个阶段，第一个阶段处理以后的数据进入第二个阶段，第二个阶段处理以后的数据进入第三个阶段……。\n",
    "\n",
    "#### 拆分数组\n",
    "\n",
    "```python\n",
    "{'$unwind': '$字段名'}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 连接数据库\n",
    "\n",
    "import pymongo\n",
    "handler = pymongo.MongoClient().chapter_7.example_data_3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': ['S', 'M', 'L', 'XL'], 'price': [100, 200, 300, 800]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': ['L', 'XL'], 'price': [150, 156]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': ['S', 'XL'], 'price': [888, 1000]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19e'), 'name': '帽子', 'size': ['M'], 'price': ['88']}\n"
     ]
    }
   ],
   "source": [
    "# 原始数据\n",
    "\n",
    "rows = handler.find()\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'S', 'price': [100, 200, 300, 800]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'M', 'price': [100, 200, 300, 800]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'L', 'price': [100, 200, 300, 800]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'XL', 'price': [100, 200, 300, 800]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': 'L', 'price': [150, 156]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': 'XL', 'price': [150, 156]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': 'S', 'price': [888, 1000]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': 'XL', 'price': [888, 1000]}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19e'), 'name': '帽子', 'size': 'M', 'price': ['88']}\n"
     ]
    }
   ],
   "source": [
    "rows = handler.aggregate([\n",
    "    {'$unwind': '$size'}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "ename": "OperationFailure",
     "evalue": "path option to $unwind stage should be prefixed with a '$': size",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mOperationFailure\u001b[0m                          Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-11-f6b0262f9fe8>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# 如果不加$符号，必定报错\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      2\u001b[0m rows = handler.aggregate([\n\u001b[0;32m----> 3\u001b[0;31m     \u001b[0;34m{\u001b[0m\u001b[0;34m'$unwind'\u001b[0m\u001b[0;34m:\u001b[0m \u001b[0;34m'size'\u001b[0m\u001b[0;34m}\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      4\u001b[0m ])\n\u001b[1;32m      5\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mrow\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrows\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/collection.py\u001b[0m in \u001b[0;36maggregate\u001b[0;34m(self, pipeline, **kwargs)\u001b[0m\n\u001b[1;32m   1868\u001b[0m                     result = self._command(sock_info, cmd, slave_ok,\n\u001b[1;32m   1869\u001b[0m                                            \u001b[0mread_concern\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread_concern\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m-> 1870\u001b[0;31m                                            collation=collation)\n\u001b[0m\u001b[1;32m   1871\u001b[0m             \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m   1872\u001b[0m                 result = self._command(sock_info, cmd, slave_ok,\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/collection.py\u001b[0m in \u001b[0;36m_command\u001b[0;34m(self, sock_info, command, slave_ok, read_preference, codec_options, check, allowable_errors, read_concern, write_concern, parse_write_concern_error, collation)\u001b[0m\n\u001b[1;32m    230\u001b[0m             \u001b[0mwrite_concern\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwrite_concern\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    231\u001b[0m             \u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 232\u001b[0;31m             collation=collation)\n\u001b[0m\u001b[1;32m    233\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    234\u001b[0m     \u001b[0;32mdef\u001b[0m \u001b[0m__create\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0moptions\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcollation\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/pool.py\u001b[0m in \u001b[0;36mcommand\u001b[0;34m(self, dbname, spec, slave_ok, read_preference, codec_options, check, allowable_errors, check_keys, read_concern, write_concern, parse_write_concern_error, collation)\u001b[0m\n\u001b[1;32m    417\u001b[0m                            \u001b[0mread_concern\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    418\u001b[0m                            \u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mparse_write_concern_error\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 419\u001b[0;31m                            collation=collation)\n\u001b[0m\u001b[1;32m    420\u001b[0m         \u001b[0;32mexcept\u001b[0m \u001b[0mOperationFailure\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    421\u001b[0m             \u001b[0;32mraise\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/network.py\u001b[0m in \u001b[0;36mcommand\u001b[0;34m(sock, dbname, spec, slave_ok, is_mongos, read_preference, codec_options, check, allowable_errors, address, check_keys, listeners, max_bson_size, read_concern, parse_write_concern_error, collation)\u001b[0m\n\u001b[1;32m    114\u001b[0m             helpers._check_command_response(\n\u001b[1;32m    115\u001b[0m                 \u001b[0mresponse_doc\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mallowable_errors\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 116\u001b[0;31m                 parse_write_concern_error=parse_write_concern_error)\n\u001b[0m\u001b[1;32m    117\u001b[0m     \u001b[0;32mexcept\u001b[0m \u001b[0mException\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mexc\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    118\u001b[0m         \u001b[0;32mif\u001b[0m \u001b[0mpublish\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;32m~/anaconda3/lib/python3.6/site-packages/pymongo/helpers.py\u001b[0m in \u001b[0;36m_check_command_response\u001b[0;34m(response, msg, allowable_errors, parse_write_concern_error)\u001b[0m\n\u001b[1;32m    208\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    209\u001b[0m             \u001b[0mmsg\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mmsg\u001b[0m \u001b[0;32mor\u001b[0m \u001b[0;34m\"%s\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 210\u001b[0;31m             \u001b[0;32mraise\u001b[0m \u001b[0mOperationFailure\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmsg\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0merrmsg\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcode\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mresponse\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m    211\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m    212\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
      "\u001b[0;31mOperationFailure\u001b[0m: path option to $unwind stage should be prefixed with a '$': size"
     ]
    }
   ],
   "source": [
    "# 如果不加$符号，必定报错\n",
    "rows = handler.aggregate([\n",
    "    {'$unwind': 'size'}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': ['S', 'M', 'L', 'XL'], 'price': 100}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': ['S', 'M', 'L', 'XL'], 'price': 200}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': ['S', 'M', 'L', 'XL'], 'price': 300}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': ['S', 'M', 'L', 'XL'], 'price': 800}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': ['L', 'XL'], 'price': 150}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': ['L', 'XL'], 'price': 156}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': ['S', 'XL'], 'price': 888}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': ['S', 'XL'], 'price': 1000}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19e'), 'name': '帽子', 'size': ['M'], 'price': '88'}\n"
     ]
    }
   ],
   "source": [
    "rows = handler.aggregate([\n",
    "    {'$unwind': '$price'}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'S', 'price': 100}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'S', 'price': 200}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'S', 'price': 300}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'S', 'price': 800}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'M', 'price': 100}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'M', 'price': 200}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'M', 'price': 300}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'M', 'price': 800}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'L', 'price': 100}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'L', 'price': 200}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'L', 'price': 300}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'L', 'price': 800}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'XL', 'price': 100}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'XL', 'price': 200}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'XL', 'price': 300}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19b'), 'name': '衬衣', 'size': 'XL', 'price': 800}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': 'L', 'price': 150}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': 'L', 'price': 156}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': 'XL', 'price': 150}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19c'), 'name': '裤子', 'size': 'XL', 'price': 156}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': 'S', 'price': 888}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': 'S', 'price': 1000}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': 'XL', 'price': 888}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19d'), 'name': '鞋子', 'size': 'XL', 'price': 1000}\n",
      "{'_id': ObjectId('5b13b3dc6b78a645a846d19e'), 'name': '帽子', 'size': 'M', 'price': '88'}\n"
     ]
    }
   ],
   "source": [
    "# 全部拆开\n",
    "\n",
    "rows = handler.aggregate([\n",
    "    {'$unwind': '$size'},\n",
    "    {'$unwind': '$price'}\n",
    "])\n",
    "for row in rows:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![读者交流QQ群](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-16-09-59-56.png)\n",
    "![微信公众号](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/wechatplatform.jpg)\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-20-47-47.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "## MongoDB的聚合查询（四）——联集合查询\n",
    "\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-16-52-34.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MongoDB的聚合操作\n",
    "\n",
    "作为一个数据库，MongoDB除了基本的增删改查外，还能进行一些统计运算和数据处理。聚合查询(aggregation)就是MongoDB进行数据处理的工具之一。聚合查询是把多个不同的阶段（stage）组合在一起，从而处理数据。\n",
    "\n",
    "### 基本语法\n",
    "\n",
    "```python\n",
    "collection.aggregate([阶段1, 阶段2, 阶段3, ..., 阶段n])\n",
    "```\n",
    "\n",
    "每一个阶段都是一个字典。一个聚合查询可以有0个、1个或者多个阶段。数据先进入第一个阶段，第一个阶段处理以后的数据进入第二个阶段，第二个阶段处理以后的数据进入第三个阶段……。\n",
    "\n",
    "#### 联集合查询\n",
    "\n",
    "\n",
    "```python\n",
    "{'$lookup': {\n",
    "        'from': '被查询的集合名',\n",
    "        'localField': '主集合字段',\n",
    "        'foreignField': '被查集合的字段',\n",
    "        'as': '查询结果被保存的字段名'\n",
    "    }\n",
    "}\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# 连接数据库\n",
    "\n",
    "import pymongo\n",
    "db = pymongo.MongoClient().chapter_7\n",
    "post = db.example_post\n",
    "user = db.example_user"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "  'age': 17,\n",
      "  'id': 1001,\n",
      "  'name': '王小一',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad77b'),\n",
      "               'content': '好不容易放假，楼上装修太吵了',\n",
      "               'post_time': '2018-06-12 08:23:12',\n",
      "               'user_id': 1001},\n",
      "             { '_id': ObjectId('5b1b83a66b78a633856ad783'),\n",
      "               'content': '青山不改绿水长流，同学们后会有期',\n",
      "               'post_time': '2018-06-15 23:23:12',\n",
      "               'user_id': 1001}],\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ad'),\n",
      "  'age': 18,\n",
      "  'id': 1002,\n",
      "  'name': '张小二',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad777'),\n",
      "               'content': '考试完了，好无聊啊啊',\n",
      "               'post_time': '2018-06-11 12:23:12',\n",
      "               'user_id': 1002},\n",
      "             { '_id': ObjectId('5b1b83a66b78a633856ad77a'),\n",
      "               'content': '我们不知道还能在一起多久',\n",
      "               'post_time': '2018-06-12 00:23:12',\n",
      "               'user_id': 1002}],\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ae'),\n",
      "  'age': 19,\n",
      "  'id': 1003,\n",
      "  'name': '李小三',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad778'),\n",
      "               'content': '大家看我今天吃得什么[图片]',\n",
      "               'post_time': '2018-06-11 12:27:12',\n",
      "               'user_id': 1003},\n",
      "             { '_id': ObjectId('5b1b83a66b78a633856ad784'),\n",
      "               'content': '今天收到了小费。谢谢大老板。',\n",
      "               'post_time': '2018-06-15 23:23:12',\n",
      "               'user_id': 1003}],\n",
      "  'work': '服务员'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1af'),\n",
      "  'age': 20,\n",
      "  'id': 1004,\n",
      "  'name': '郭小四',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad77c'),\n",
      "               'content': '疯了疯了疯了，我把洗衣服当成盐了',\n",
      "               'post_time': '2018-06-12 17:23:12',\n",
      "               'user_id': 1004},\n",
      "             { '_id': ObjectId('5b1b83a66b78a633856ad77d'),\n",
      "               'content': '此处不留爷，自有留爷处',\n",
      "               'post_time': '2018-06-12 21:23:12',\n",
      "               'user_id': 1004}],\n",
      "  'work': '厨师'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b0'),\n",
      "  'age': 21,\n",
      "  'id': 1005,\n",
      "  'name': '毛小五',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad77e'),\n",
      "               'content': '这个厕所设计得太美了',\n",
      "               'post_time': '2018-06-13 09:23:12',\n",
      "               'user_id': 1005},\n",
      "             { '_id': ObjectId('5b1b83a66b78a633856ad780'),\n",
      "               'content': 'XX显示器的色彩太好看了',\n",
      "               'post_time': '2018-06-14 10:23:12',\n",
      "               'user_id': 1005}],\n",
      "  'work': '美工'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b1'),\n",
      "  'age': 22,\n",
      "  'id': 1006,\n",
      "  'name': '欧阳小六',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad779'),\n",
      "               'content': 'XX外卖送货太慢了，差评',\n",
      "               'post_time': '2018-06-11 14:00:12',\n",
      "               'user_id': 1006}],\n",
      "  'work': '工程师'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b2'),\n",
      "  'age': 23,\n",
      "  'id': 1007,\n",
      "  'name': '夏侯小七',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad77f'),\n",
      "               'content': 'XX叔，一路走好',\n",
      "               'post_time': '2018-06-13 17:23:12',\n",
      "               'user_id': 1007}],\n",
      "  'work': '医生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b3'),\n",
      "  'age': 24,\n",
      "  'id': 1008,\n",
      "  'name': '慕容小八',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad781'),\n",
      "               'content': '我在X市参与城市规划',\n",
      "               'post_time': '2018-06-15 12:01:12',\n",
      "               'user_id': 1008}],\n",
      "  'work': '建筑设计师'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b4'),\n",
      "  'age': 25,\n",
      "  'id': 1009,\n",
      "  'name': '南宫小九',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': [ { '_id': ObjectId('5b1b83a66b78a633856ad782'),\n",
      "               'content': '小九中介竭诚为你服务',\n",
      "               'post_time': '2018-06-15 15:23:12',\n",
      "               'user_id': 1009}],\n",
      "  'work': '中介'}\n"
     ]
    }
   ],
   "source": [
    "# 以example_user 为主集合，查询每个用户发送的所有微博\n",
    "from pprint import pprint\n",
    "\n",
    "weibo_per_user = user.aggregate([\n",
    "    {'$lookup': {\n",
    "        'from': 'example_post',\n",
    "        'localField': 'id',\n",
    "        'foreignField': 'user_id',\n",
    "        'as': 'weibo'\n",
    "    }}\n",
    "])\n",
    "\n",
    "for row in weibo_per_user:\n",
    "    pprint(row, indent=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ '_id': ObjectId('5b1b83a66b78a633856ad777'),\n",
      "  'content': '考试完了，好无聊啊啊',\n",
      "  'post_time': '2018-06-11 12:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1ad'),\n",
      "              'age': 18,\n",
      "              'id': 1002,\n",
      "              'name': '张小二',\n",
      "              'register_date': '2018-06-09',\n",
      "              'work': '学生'}],\n",
      "  'user_id': 1002}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad778'),\n",
      "  'content': '大家看我今天吃得什么[图片]',\n",
      "  'post_time': '2018-06-11 12:27:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1ae'),\n",
      "              'age': 19,\n",
      "              'id': 1003,\n",
      "              'name': '李小三',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '服务员'}],\n",
      "  'user_id': 1003}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad779'),\n",
      "  'content': 'XX外卖送货太慢了，差评',\n",
      "  'post_time': '2018-06-11 14:00:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1b1'),\n",
      "              'age': 22,\n",
      "              'id': 1006,\n",
      "              'name': '欧阳小六',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '工程师'}],\n",
      "  'user_id': 1006}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad77a'),\n",
      "  'content': '我们不知道还能在一起多久',\n",
      "  'post_time': '2018-06-12 00:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1ad'),\n",
      "              'age': 18,\n",
      "              'id': 1002,\n",
      "              'name': '张小二',\n",
      "              'register_date': '2018-06-09',\n",
      "              'work': '学生'}],\n",
      "  'user_id': 1002}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad77b'),\n",
      "  'content': '好不容易放假，楼上装修太吵了',\n",
      "  'post_time': '2018-06-12 08:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "              'age': 17,\n",
      "              'id': 1001,\n",
      "              'name': '王小一',\n",
      "              'register_date': '2018-06-09',\n",
      "              'work': '学生'}],\n",
      "  'user_id': 1001}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad77c'),\n",
      "  'content': '疯了疯了疯了，我把洗衣服当成盐了',\n",
      "  'post_time': '2018-06-12 17:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1af'),\n",
      "              'age': 20,\n",
      "              'id': 1004,\n",
      "              'name': '郭小四',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '厨师'}],\n",
      "  'user_id': 1004}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad77d'),\n",
      "  'content': '此处不留爷，自有留爷处',\n",
      "  'post_time': '2018-06-12 21:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1af'),\n",
      "              'age': 20,\n",
      "              'id': 1004,\n",
      "              'name': '郭小四',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '厨师'}],\n",
      "  'user_id': 1004}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad77e'),\n",
      "  'content': '这个厕所设计得太美了',\n",
      "  'post_time': '2018-06-13 09:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1b0'),\n",
      "              'age': 21,\n",
      "              'id': 1005,\n",
      "              'name': '毛小五',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '美工'}],\n",
      "  'user_id': 1005}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad77f'),\n",
      "  'content': 'XX叔，一路走好',\n",
      "  'post_time': '2018-06-13 17:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1b2'),\n",
      "              'age': 23,\n",
      "              'id': 1007,\n",
      "              'name': '夏侯小七',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '医生'}],\n",
      "  'user_id': 1007}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad780'),\n",
      "  'content': 'XX显示器的色彩太好看了',\n",
      "  'post_time': '2018-06-14 10:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1b0'),\n",
      "              'age': 21,\n",
      "              'id': 1005,\n",
      "              'name': '毛小五',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '美工'}],\n",
      "  'user_id': 1005}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad781'),\n",
      "  'content': '我在X市参与城市规划',\n",
      "  'post_time': '2018-06-15 12:01:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1b3'),\n",
      "              'age': 24,\n",
      "              'id': 1008,\n",
      "              'name': '慕容小八',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '建筑设计师'}],\n",
      "  'user_id': 1008}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad782'),\n",
      "  'content': '小九中介竭诚为你服务',\n",
      "  'post_time': '2018-06-15 15:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1b4'),\n",
      "              'age': 25,\n",
      "              'id': 1009,\n",
      "              'name': '南宫小九',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '中介'}],\n",
      "  'user_id': 1009}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad783'),\n",
      "  'content': '青山不改绿水长流，同学们后会有期',\n",
      "  'post_time': '2018-06-15 23:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "              'age': 17,\n",
      "              'id': 1001,\n",
      "              'name': '王小一',\n",
      "              'register_date': '2018-06-09',\n",
      "              'work': '学生'}],\n",
      "  'user_id': 1001}\n",
      "{ '_id': ObjectId('5b1b83a66b78a633856ad784'),\n",
      "  'content': '今天收到了小费。谢谢大老板。',\n",
      "  'post_time': '2018-06-15 23:23:12',\n",
      "  'user': [ { '_id': ObjectId('5b1b81266b78a632394ab1ae'),\n",
      "              'age': 19,\n",
      "              'id': 1003,\n",
      "              'name': '李小三',\n",
      "              'register_date': '2018-06-10',\n",
      "              'work': '服务员'}],\n",
      "  'user_id': 1003}\n"
     ]
    }
   ],
   "source": [
    "# 以example_post 为主集合，查询每个用户发送的所有微博\n",
    "from pprint import pprint\n",
    "\n",
    "user_per_weibo = post.aggregate([\n",
    "    {'$lookup': {\n",
    "        'from': 'example_user',\n",
    "        'localField': 'user_id',\n",
    "        'foreignField': 'id',\n",
    "        'as': 'user'\n",
    "    }}\n",
    "])\n",
    "\n",
    "for row in user_per_weibo:\n",
    "    pprint(row, indent=2) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'_id': ObjectId('5b1b81266b78a632394ab1ac'), 'id': 1001, 'name': '王小一', 'register_date': '2018-06-09', 'age': 17, 'work': '学生', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad77b'), 'user_id': 1001, 'content': '好不容易放假，楼上装修太吵了', 'post_time': '2018-06-12 08:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1ac'), 'id': 1001, 'name': '王小一', 'register_date': '2018-06-09', 'age': 17, 'work': '学生', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad783'), 'user_id': 1001, 'content': '青山不改绿水长流，同学们后会有期', 'post_time': '2018-06-15 23:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1ad'), 'id': 1002, 'name': '张小二', 'register_date': '2018-06-09', 'age': 18, 'work': '学生', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad777'), 'user_id': 1002, 'content': '考试完了，好无聊啊啊', 'post_time': '2018-06-11 12:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1ad'), 'id': 1002, 'name': '张小二', 'register_date': '2018-06-09', 'age': 18, 'work': '学生', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad77a'), 'user_id': 1002, 'content': '我们不知道还能在一起多久', 'post_time': '2018-06-12 00:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1ae'), 'id': 1003, 'name': '李小三', 'register_date': '2018-06-10', 'age': 19, 'work': '服务员', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad778'), 'user_id': 1003, 'content': '大家看我今天吃得什么[图片]', 'post_time': '2018-06-11 12:27:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1ae'), 'id': 1003, 'name': '李小三', 'register_date': '2018-06-10', 'age': 19, 'work': '服务员', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad784'), 'user_id': 1003, 'content': '今天收到了小费。谢谢大老板。', 'post_time': '2018-06-15 23:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1af'), 'id': 1004, 'name': '郭小四', 'register_date': '2018-06-10', 'age': 20, 'work': '厨师', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad77c'), 'user_id': 1004, 'content': '疯了疯了疯了，我把洗衣服当成盐了', 'post_time': '2018-06-12 17:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1af'), 'id': 1004, 'name': '郭小四', 'register_date': '2018-06-10', 'age': 20, 'work': '厨师', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad77d'), 'user_id': 1004, 'content': '此处不留爷，自有留爷处', 'post_time': '2018-06-12 21:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1b0'), 'id': 1005, 'name': '毛小五', 'register_date': '2018-06-10', 'age': 21, 'work': '美工', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad77e'), 'user_id': 1005, 'content': '这个厕所设计得太美了', 'post_time': '2018-06-13 09:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1b0'), 'id': 1005, 'name': '毛小五', 'register_date': '2018-06-10', 'age': 21, 'work': '美工', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad780'), 'user_id': 1005, 'content': 'XX显示器的色彩太好看了', 'post_time': '2018-06-14 10:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1b1'), 'id': 1006, 'name': '欧阳小六', 'register_date': '2018-06-10', 'age': 22, 'work': '工程师', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad779'), 'user_id': 1006, 'content': 'XX外卖送货太慢了，差评', 'post_time': '2018-06-11 14:00:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1b2'), 'id': 1007, 'name': '夏侯小七', 'register_date': '2018-06-10', 'age': 23, 'work': '医生', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad77f'), 'user_id': 1007, 'content': 'XX叔，一路走好', 'post_time': '2018-06-13 17:23:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1b3'), 'id': 1008, 'name': '慕容小八', 'register_date': '2018-06-10', 'age': 24, 'work': '建筑设计师', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad781'), 'user_id': 1008, 'content': '我在X市参与城市规划', 'post_time': '2018-06-15 12:01:12'}}\n",
      "{'_id': ObjectId('5b1b81266b78a632394ab1b4'), 'id': 1009, 'name': '南宫小九', 'register_date': '2018-06-10', 'age': 25, 'work': '中介', 'weibo': {'_id': ObjectId('5b1b83a66b78a633856ad782'), 'user_id': 1009, 'content': '小九中介竭诚为你服务', 'post_time': '2018-06-15 15:23:12'}}\n"
     ]
    }
   ],
   "source": [
    "# 以example_user 为主集合，查询每个用户发送的所有微博，并拆开结果\n",
    "from pprint import pprint\n",
    "\n",
    "weibo_per_user = user.aggregate([\n",
    "    {'$lookup': {\n",
    "        'from': 'example_post',\n",
    "        'localField': 'id',\n",
    "        'foreignField': 'user_id',\n",
    "        'as': 'weibo'\n",
    "    }},\n",
    "    {'$unwind': '$weibo'}\n",
    "])\n",
    "\n",
    "for row in weibo_per_user:\n",
    "    print(row)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "  'age': 17,\n",
      "  'id': 1001,\n",
      "  'name': '王小一',\n",
      "  'post_time': '2018-06-12 08:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '好不容易放假，楼上装修太吵了',\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "  'age': 17,\n",
      "  'id': 1001,\n",
      "  'name': '王小一',\n",
      "  'post_time': '2018-06-15 23:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '青山不改绿水长流，同学们后会有期',\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ad'),\n",
      "  'age': 18,\n",
      "  'id': 1002,\n",
      "  'name': '张小二',\n",
      "  'post_time': '2018-06-11 12:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '考试完了，好无聊啊啊',\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ad'),\n",
      "  'age': 18,\n",
      "  'id': 1002,\n",
      "  'name': '张小二',\n",
      "  'post_time': '2018-06-12 00:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '我们不知道还能在一起多久',\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ae'),\n",
      "  'age': 19,\n",
      "  'id': 1003,\n",
      "  'name': '李小三',\n",
      "  'post_time': '2018-06-11 12:27:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': '大家看我今天吃得什么[图片]',\n",
      "  'work': '服务员'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ae'),\n",
      "  'age': 19,\n",
      "  'id': 1003,\n",
      "  'name': '李小三',\n",
      "  'post_time': '2018-06-15 23:23:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': '今天收到了小费。谢谢大老板。',\n",
      "  'work': '服务员'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1af'),\n",
      "  'age': 20,\n",
      "  'id': 1004,\n",
      "  'name': '郭小四',\n",
      "  'post_time': '2018-06-12 17:23:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': '疯了疯了疯了，我把洗衣服当成盐了',\n",
      "  'work': '厨师'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1af'),\n",
      "  'age': 20,\n",
      "  'id': 1004,\n",
      "  'name': '郭小四',\n",
      "  'post_time': '2018-06-12 21:23:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': '此处不留爷，自有留爷处',\n",
      "  'work': '厨师'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b0'),\n",
      "  'age': 21,\n",
      "  'id': 1005,\n",
      "  'name': '毛小五',\n",
      "  'post_time': '2018-06-13 09:23:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': '这个厕所设计得太美了',\n",
      "  'work': '美工'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b0'),\n",
      "  'age': 21,\n",
      "  'id': 1005,\n",
      "  'name': '毛小五',\n",
      "  'post_time': '2018-06-14 10:23:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': 'XX显示器的色彩太好看了',\n",
      "  'work': '美工'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b1'),\n",
      "  'age': 22,\n",
      "  'id': 1006,\n",
      "  'name': '欧阳小六',\n",
      "  'post_time': '2018-06-11 14:00:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': 'XX外卖送货太慢了，差评',\n",
      "  'work': '工程师'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b2'),\n",
      "  'age': 23,\n",
      "  'id': 1007,\n",
      "  'name': '夏侯小七',\n",
      "  'post_time': '2018-06-13 17:23:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': 'XX叔，一路走好',\n",
      "  'work': '医生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b3'),\n",
      "  'age': 24,\n",
      "  'id': 1008,\n",
      "  'name': '慕容小八',\n",
      "  'post_time': '2018-06-15 12:01:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': '我在X市参与城市规划',\n",
      "  'work': '建筑设计师'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1b4'),\n",
      "  'age': 25,\n",
      "  'id': 1009,\n",
      "  'name': '南宫小九',\n",
      "  'post_time': '2018-06-15 15:23:12',\n",
      "  'register_date': '2018-06-10',\n",
      "  'weibo': '小九中介竭诚为你服务',\n",
      "  'work': '中介'}\n"
     ]
    }
   ],
   "source": [
    "# 以example_user 为主集合，查询每个用户发送的所有微博，并拆开结果，再提取字段出来\n",
    "import json\n",
    "from pprint import pprint\n",
    "\n",
    "weibo_per_user = user.aggregate([\n",
    "    {'$lookup': {\n",
    "        'from': 'example_post',\n",
    "        'localField': 'id',\n",
    "        'foreignField': 'user_id',\n",
    "        'as': 'weibo'\n",
    "    }},\n",
    "    {'$unwind': '$weibo'},\n",
    "    {'$project': {\n",
    "        'id': 1,\n",
    "        'name': 1,\n",
    "        'register_date': 1,\n",
    "        'age': 1,\n",
    "        'work': 1, \n",
    "        'weibo': '$weibo.content',\n",
    "        'post_time': '$weibo.post_time'\n",
    "    }}\n",
    "])\n",
    "\n",
    "for row in weibo_per_user:\n",
    "    pprint(row, indent=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "  'age': 17,\n",
      "  'id': 1001,\n",
      "  'name': '王小一',\n",
      "  'post_time': '2018-06-12 08:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '好不容易放假，楼上装修太吵了',\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "  'age': 17,\n",
      "  'id': 1001,\n",
      "  'name': '王小一',\n",
      "  'post_time': '2018-06-15 23:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '青山不改绿水长流，同学们后会有期',\n",
      "  'work': '学生'}\n"
     ]
    }
   ],
   "source": [
    "# 以example_user 为主集合，查询特定用户发送的所有微博，并拆开结果，再提取字段出来\n",
    "import json\n",
    "from pprint import pprint\n",
    "\n",
    "weibo_per_user = user.aggregate([\n",
    "    {'$match': {'name': '王小一'}},\n",
    "    {'$lookup': {\n",
    "        'from': 'example_post',\n",
    "        'localField': 'id',\n",
    "        'foreignField': 'user_id',\n",
    "        'as': 'weibo'\n",
    "    }},\n",
    "    {'$unwind': '$weibo'},\n",
    "    {'$project': {\n",
    "        'id': 1,\n",
    "        'name': 1,\n",
    "        'register_date': 1,\n",
    "        'age': 1,\n",
    "        'work': 1, \n",
    "        'weibo': '$weibo.content',\n",
    "        'post_time': '$weibo.post_time'\n",
    "    }}\n",
    "])\n",
    "\n",
    "for row in weibo_per_user:\n",
    "    pprint(row, indent=2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "  'age': 17,\n",
      "  'id': 1001,\n",
      "  'name': '王小一',\n",
      "  'post_time': '2018-06-12 08:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '好不容易放假，楼上装修太吵了',\n",
      "  'work': '学生'}\n",
      "{ '_id': ObjectId('5b1b81266b78a632394ab1ac'),\n",
      "  'age': 17,\n",
      "  'id': 1001,\n",
      "  'name': '王小一',\n",
      "  'post_time': '2018-06-15 23:23:12',\n",
      "  'register_date': '2018-06-09',\n",
      "  'weibo': '青山不改绿水长流，同学们后会有期',\n",
      "  'work': '学生'}\n"
     ]
    }
   ],
   "source": [
    "# 以example_user 为主集合，查询所有用户发送的所有微博，并拆开结果，再提取字段出来，最后筛选特定用户\n",
    "import json\n",
    "from pprint import pprint\n",
    "\n",
    "weibo_per_user = user.aggregate([\n",
    "    {'$lookup': {\n",
    "        'from': 'example_post',\n",
    "        'localField': 'id',\n",
    "        'foreignField': 'user_id',\n",
    "        'as': 'weibo'\n",
    "    }},\n",
    "    {'$unwind': '$weibo'},\n",
    "    {'$project': {\n",
    "        'id': 1,\n",
    "        'name': 1,\n",
    "        'register_date': 1,\n",
    "        'age': 1,\n",
    "        'work': 1, \n",
    "        'weibo': '$weibo.content',\n",
    "        'post_time': '$weibo.post_time'\n",
    "    }},\n",
    "    {'$match': {'name': '王小一'}}\n",
    "])\n",
    "\n",
    "for row in weibo_per_user:\n",
    "    pprint(row, indent=2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![读者交流QQ群](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-02-16-09-59-56.png)\n",
    "![微信公众号](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/wechatplatform.jpg)\n",
    "![](https://kingname-1257411235.cos.ap-chengdu.myqcloud.com/2019-03-03-20-47-47.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
